home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d892.lha / Indent / source / source.lha / pr_comment.c < prev    next >
C/C++ Source or Header  |  1993-06-11  |  15KB  |  566 lines

  1. /* Copyright (c) 1993, Joseph Arceneaux.
  2.  
  3.    This file is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 1, or (at your option)
  6.    any later version.
  7.  
  8.    This software is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    If you do not have a copy of the GNU General Public License, you
  14.    may obtain a copy by writing to the Free Software Foundation,
  15.    675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17.  
  18.  
  19. #include "sys.h"
  20. #include "indent.h"
  21.  
  22. /* Check the limits of the comment buffer, and expand as neccessary. */
  23.  
  24. #define CHECK_COM_SIZE \
  25.     if (e_com >= l_com) \
  26.           { \
  27.         register nsize = l_com-s_com+400; \
  28.         combuf = (char *) xrealloc (combuf, nsize); \
  29.         e_com = combuf + (e_com-s_com) + 1; \
  30.         l_com = combuf + nsize - 5; \
  31.         s_com = combuf + 1; \
  32.       }
  33.  
  34. /* The number of comments handled so far. */
  35. int out_coms;
  36.  
  37. /* Output a comment.  `buf_ptr' is pointing to the character after
  38.    the beginning comment delimiter when this is called.  This handles
  39.    both C and C++ comments.
  40.  
  41.    As far as indent is concerned, there are basically two types
  42.    of comments -- those on lines by themselves and those which are
  43.    on lines with other code.  Variables (and the options specifying them)
  44.    affecting the printing of comments are:
  45.  
  46.    `format_comments'                ("fca"):  Ignore newlines in the
  47.        comment and perform filling up to `max_col'.  Double newlines
  48.        indicate paragraph breaks.
  49.  
  50.    `format_col1_comments'           ("fc1"):  Format comments which
  51.        begin in column 1.
  52.  
  53.    `unindent_displace'              ("d"):  The hanging indentation for
  54.        comments which do not appear to the right of code.
  55.  
  56.    `comment_delimiter_on_blankline' ("cdb"):  If set, place the comment
  57.        delimiters on lines by themselves.  This only affects comments
  58.        which are not to the right of code.
  59.  
  60.    `com_ind'                        ("c"):  The column in which to begin
  61.        comments that are to the right of code.
  62.  
  63.    `decl_com_ind'                   ("cd"):  The column in which to begin
  64.        comments that are to the right of declarations.
  65.  
  66.    `else_endif_col'                 ("cp"):  The column in which to begin
  67.        comments to the right of preprocessor directives.
  68.  
  69.    `star_comment_cont'              ("sc"):  Place a star ('*') to the
  70.        left of the comment body.
  71.  
  72.    `max_col'                        ("l"):  The length of a line.  Formatted
  73.        comments which extend past this column will be continued on the
  74.        following line.
  75.  
  76.    `block_comment_max_col'          ("lc"): Unused.
  77.  
  78.    `blanklines_before_blockcomments'("nbbb"): Unused.
  79.  
  80.    */
  81.  
  82. void
  83. print_comment ()
  84. {
  85.   register int column, format;
  86.   enum codes comment_type;
  87.  
  88.   int start_column, save_length, found_column;
  89.   int first_comment_line, right_margin;
  90.   int boxed_comment, stars, blankline_delims, paragraph_break,
  91.       merge_blank_comment_lines;
  92.   char *line_break_ptr = 0;
  93.   char *save_ptr = 0;
  94.   char *text_on_line = 0;
  95.   char *start_delim, *end_delim;
  96.  
  97.   char *line_preamble;
  98.   int line_preamble_length, visible_preamble;
  99.  
  100.   /* Increment the parser stack, as we will store some things
  101.      there for dump_line to use. */
  102.   inc_pstack ();
  103.  
  104.   /* Have to do it this way because this piece of shit program doesn't
  105.      always place the last token code on the stack. */
  106.   if (*(token + 1) == '/')
  107.     comment_type = cplus_comment;
  108.   else
  109.     comment_type = comment;
  110.  
  111.   /* First, decide what kind of comment this is: C++, C, or boxed C.
  112.      Even if this appears to be a normal C comment, we may change our
  113.      minds if we find a star in the right column of the second line,
  114.      in which case that's a boxed comment too. */
  115.   if (comment_type == cplus_comment)
  116.     {
  117.       start_delim = "//";
  118.       line_preamble = "// ";
  119.       line_preamble_length = 3;
  120.       visible_preamble = 1;
  121.       boxed_comment = 0;
  122.       stars = 0;
  123.       blankline_delims = 0;
  124.     }
  125.   else if (*buf_ptr == '*' || *buf_ptr == '-'
  126.        || *buf_ptr == '=' || *buf_ptr == '_')
  127.     /* Boxed comment */
  128.     {
  129.       start_delim = "/*";
  130.       end_delim = "*/";
  131.       line_preamble = " ";
  132.       line_preamble_length = 1;
  133.       visible_preamble = 0;
  134.       boxed_comment = 1;
  135.       stars = 0;
  136.       blankline_delims = 0;
  137.     }
  138.   else
  139.     {
  140.       start_delim = "/*";
  141.       end_delim = "*/";
  142.       line_preamble = 0;
  143.       line_preamble_length = 0;
  144.       visible_preamble = 0;
  145.       boxed_comment = 0;
  146.       stars = star_comment_cont;
  147.       blankline_delims = comment_delimiter_on_blankline;
  148.     }
  149.  
  150.   paragraph_break = 0;
  151.   merge_blank_comment_lines = 0;
  152.   first_comment_line = com_lines;
  153.   right_margin = max_col;
  154.  
  155.   /* Now, compute the correct indentation for this comment
  156.      and whether or not it should be formatted. */
  157.   found_column = current_column () - 2;
  158.   if (boxed_comment)
  159.     {
  160.       start_column = found_column;
  161.       format = 0;
  162.       blankline_delims = 0;
  163.     }
  164.   else
  165.     {
  166.       /* First handle comments which begin the line. */
  167.       if ((s_lab == e_lab) && (s_code == e_code))
  168.     {
  169.       /* This is a top-level comment, not within some code. */
  170.       if (parser_state_tos->ind_level <= 0)
  171.         {
  172.           if (parser_state_tos->col_1)
  173.         {
  174.           format = format_col1_comments;
  175.           start_column = 1;
  176.         }
  177.           else
  178.         {
  179.           format = format_comments;
  180.           start_column = found_column;
  181.         }
  182.         }
  183.       /* Here for comments starting a line, in the middle of code. */
  184.       else
  185.         {
  186.           if (parser_state_tos->col_1)
  187.         {
  188.           format = format_col1_comments;
  189.           start_column = 1;
  190.         }
  191.           else
  192.         {
  193.           format = format_comments;
  194.           start_column = (parser_state_tos->ind_level
  195.                   - unindent_displace + 1);
  196.           if (start_column < 0)
  197.             start_column = 1;
  198.         }
  199.         }
  200.     }
  201.       else
  202.     /* This comment follows code of some sort. */
  203.     {
  204.       int target;
  205.  
  206.       /* First, compute where the comment SHOULD go. */
  207.       if (parser_state_tos->decl_on_line)
  208.         target = decl_com_ind;
  209.       else if (else_or_endif)
  210.         target = else_endif_col;
  211.       else
  212.         target = com_ind;
  213.  
  214.       /* Now determine if the code on the line is short enough
  215.          to allow the comment to begin where it should. */
  216.       if (s_code != e_code)
  217.         start_column = count_columns (compute_code_target (), s_code);
  218.       else
  219.         /* s_lab != e_lab : there is a label here. */
  220.         start_column = count_columns (compute_label_target (), s_lab);
  221.  
  222.       if (start_column < target)
  223.         start_column = target;
  224.       else
  225.         {
  226.           /* If the too-long code is a pre-processor command,
  227.          start the comment 1 space afterwards, otherwise
  228.          start at the next tab mark. */
  229.           if (else_or_endif)
  230.         {
  231.           start_column++;
  232.           else_or_endif = false;
  233.         }
  234.           else
  235.         start_column += (tabsize - (start_column % tabsize) + 1);
  236.         }
  237.  
  238.       format = format_comments;
  239.     }
  240.     }
  241.  
  242.   if (! line_preamble)
  243.     {
  244.       line_preamble_length = 3;
  245.       if (stars)
  246.     {
  247.       line_preamble = " * ";
  248.       visible_preamble = 1;
  249.     }
  250.       else
  251.     {
  252.       line_preamble = "   ";
  253.       visible_preamble = 0;
  254.     }
  255.     }
  256.  
  257.   /* These are the parser stack variables used to communicate
  258.      formatting information to dump_line (). */
  259.   parser_state_tos->com_col = start_column;
  260.   parser_state_tos->box_com = boxed_comment;
  261.   if (boxed_comment)
  262.     {
  263.       stars = 0;
  264.       blankline_delims = 0;
  265.     }
  266.  
  267.   /* Output the beginning comment delimiter.  They are both two
  268.      characters long. */
  269.   memcpy (e_com, start_delim, 2);
  270.   e_com += 2;
  271.   column = start_column + 2;
  272.  
  273.   /* If the user specified -cdb, put the delimiter on one line. */
  274.   if (blankline_delims)
  275.     {
  276.       char *p = buf_ptr;
  277.  
  278.       *e_com = '\0';
  279.       dump_line ();
  280.  
  281.       /* Check if the delimiter was already on a line by itself,
  282.      and skip whitespace if formating. */
  283.       while ((*p == ' ' || *p == TAB) && p < buf_end)
  284.     p++;
  285.       if (*p == EOL)
  286.     buf_ptr = p + 1;
  287.       else if (format)
  288.     buf_ptr = p;
  289.       if (buf_ptr >= buf_end)
  290.     fill_buffer ();
  291.  
  292.       column = start_column;
  293.       goto begin_line;
  294.     }
  295.   else if (format)
  296.     {
  297.       *e_com++ = ' ';
  298.       column = start_column + 3;
  299.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  300.     buf_ptr++;
  301.       if (buf_ptr >= buf_end)
  302.     fill_buffer ();
  303.     }
  304.  
  305.   /* Iterate through the lines of the comment */
  306.   while (1)
  307.     {
  308.       /* Iterate through the characters on one line */
  309.       while (1)
  310.     {
  311.       CHECK_COM_SIZE;
  312.  
  313.       switch (*buf_ptr)
  314.         {
  315.         case ' ':
  316.         case TAB:
  317.           /* If formatting, and previous break marker is
  318.              nonexistant, or before text on line, reset
  319.          it to here. */
  320.           if (format && line_break_ptr < text_on_line)
  321.         line_break_ptr = e_com;
  322.  
  323.           if (*buf_ptr == ' ')
  324.         {
  325.           *e_com++ = ' ';
  326.           column++;
  327.         }
  328.           else
  329.         {
  330.           /* Convert the tab to the appropriate number of spaces,
  331.              based on the column we found the comment in, not
  332.              the one we're printing in. */
  333.           int tab_width
  334.             = (tabsize - ((column + found_column - start_column - 1)
  335.                   % tabsize));
  336.           column += tab_width;
  337.           while (tab_width--)
  338.             *e_com++ = ' ';
  339.         }
  340.           break;
  341.  
  342.         case EOL:
  343.           /* We may be at the end of a C++ comment */
  344.           if (comment_type == cplus_comment)
  345.         {
  346.           dump_line ();
  347.           buf_ptr++;
  348.           if (buf_ptr >= buf_end)
  349.             fill_buffer ();
  350.  
  351.           parser_state_tos->tos--;
  352.           parser_state_tos->com_col = start_column;
  353.           return;
  354.         }
  355.  
  356.           if (format)
  357.         {
  358.           /* Newline and null are the two characters which
  359.              end an input line, so check here if we need to
  360.              get the next line. */
  361.           buf_ptr++;
  362.           if (buf_ptr >= buf_end)
  363.             fill_buffer ();
  364.  
  365.           /* If this is "\n\n", it's a paragraph break. */
  366.           if (*buf_ptr == EOL || ! text_on_line)
  367.             {
  368.               paragraph_break = 1;
  369.               goto end_line;
  370.             }
  371.  
  372.           /* This is a single newline.  Transform it, and any
  373.              following whitespace into a single blank. */
  374.           line_break_ptr = e_com;
  375.           *e_com++ = ' ';
  376.           column++;
  377.           while (*buf_ptr == TAB || *buf_ptr == ' ')
  378.             buf_ptr++;
  379.           if (buf_ptr >= buf_end)
  380.             fill_buffer ();
  381.           continue;
  382.         }
  383.           else
  384.         /* We are printing this line "as is", so output it
  385.            and continue on to the next line. */
  386.         goto end_line;
  387.           break;
  388.  
  389.         case '*':
  390.           /* Check if we've reached the end of the comment. */
  391.           if (comment_type == comment)
  392.         {
  393.           if (*(buf_ptr + 1) == '/')
  394.             {
  395.               /* If it's not a boxed comment, put some whitespace
  396.                  before the ending delimiter.  Otherwise, simply
  397.              insert the delimiter. */
  398.               if (! boxed_comment)
  399.             {
  400.               if (text_on_line)
  401.                 {
  402.                   if (blankline_delims)
  403.                 {
  404.                   *e_com = '\0';
  405.                   dump_line ();
  406.                   *e_com++ = ' ';
  407.                 }
  408.                   else
  409.                 /* Here I also tried some code to ensure
  410.                    that the ending delimiter didn't exceed
  411.                    max_col of formatted comments.  But it's
  412.                    not worth the hassle. */
  413.                 if (*(e_com - 1) != ' ')
  414.                   *e_com++ = ' ';
  415.                 }
  416.               else
  417.                 e_com = s_com + 1;
  418.             }
  419.  
  420.               *e_com++ = '*';
  421.               *e_com++ = '/';
  422.               *e_com = '\0';
  423.  
  424.               /* Skip any whitespace following the comment.  If
  425.              there is only whitespace after it, print the line. */
  426.               buf_ptr += 2;
  427.               while (*buf_ptr == ' ' || *buf_ptr == TAB)
  428.             buf_ptr++;
  429.               if (buf_ptr >= buf_end)
  430.             fill_buffer ();
  431.  
  432.               parser_state_tos->tos--;
  433.               parser_state_tos->com_col = start_column;
  434.               return;
  435.             }
  436.  
  437.           /* If this star is on the second line of the
  438.              comment in the same column as the star of the
  439.              beginning delimiter, then consider it
  440.              a boxed comment. */
  441.           if (first_comment_line == com_lines - 1
  442.               && e_com == s_com + line_preamble_length
  443.               && current_column () == start_column + 1)
  444.             {
  445.               line_preamble = " ";
  446.               line_preamble_length = 1;
  447.               boxed_comment = 1;
  448.               format = 0;
  449.               blankline_delims = 0;
  450.               *s_com = ' ';
  451.               *(s_com + 1) = '*';
  452.               e_com = s_com + 2;
  453.               column++;
  454.               break;
  455.             }
  456.         }
  457.           /* If it was not the end of the comment, drop through
  458.              and insert the star on the line. */
  459.  
  460.         default:
  461.           /* Some textual character. */
  462.           text_on_line = e_com;
  463.           *e_com++ = *buf_ptr;
  464.           column++;
  465.           break;
  466.         }
  467.  
  468.  
  469.       /* If we are formatting, check that we haven't exceeded the
  470.          line length.  If we haven't set line_break_ptr, keep going. */
  471.       if (format && column > right_margin && line_break_ptr)
  472.         {
  473.           if (line_break_ptr < e_com - 1)
  474.         {
  475.           *line_break_ptr = '\0';
  476.           save_ptr = line_break_ptr + 1;
  477.           save_length = e_com - save_ptr;
  478.           e_com = line_break_ptr;
  479.  
  480.           /* If we had to go past `right_margin' to print stuff out,
  481.              extend `right_margin' out to this point. */
  482.           if ((column - save_length) > right_margin)
  483.             right_margin = column - save_length;
  484.         }
  485.           else
  486.         *e_com = '\0';
  487.           goto end_line;
  488.         }
  489.  
  490.       buf_ptr++;
  491.     }
  492.  
  493.  
  494.     end_line:
  495.       /* Compress pure whitespace lines into newlines. */
  496.       if (! text_on_line
  497.       && ! visible_preamble
  498.       && ! (first_comment_line == com_lines))
  499.     e_com = s_com;
  500.       *e_com = '\0';
  501.       dump_line ();
  502.  
  503.       /* If formatting (paragraph_break is only used for formatted
  504.      comments) and user wants blank lines merged, kill all white
  505.      space after the "\n\n" indicating a paragraph break. */
  506.       if (paragraph_break)
  507.     {
  508.       if (merge_blank_comment_lines)
  509.         while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB)
  510.           if (++buf_ptr >= buf_end)
  511.         fill_buffer ();
  512.       paragraph_break = 0;
  513.     }
  514.       else
  515.     {
  516.       /* If it was a paragraph break (`if' clause), we scanned ahead
  517.          one character.  So, here in the `else' clause, advance buf_ptr. */
  518.       buf_ptr++;
  519.       if (buf_ptr >= buf_end)
  520.         fill_buffer ();
  521.     }
  522.  
  523.     begin_line:
  524.       /* Indent the line properly.  If it's a boxed comment, align with
  525.      the '*' in the beginning slash-star and start inserting there.
  526.      Otherwise, insert blanks for alignment, or a star if the
  527.      user specified -sc. */
  528.       if (line_preamble)
  529.     {
  530.       memcpy (e_com, line_preamble, line_preamble_length);
  531.       e_com += line_preamble_length;
  532.       column = start_column + line_preamble_length;
  533.     }
  534.       else
  535.     column = start_column;
  536.       line_break_ptr = 0;
  537.  
  538.       /* If we have broken the line before the end for formatting,
  539.          copy the text after the break onto the beginning of this
  540.      new comment line. */
  541.       if (save_ptr)
  542.     {
  543.       while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length)
  544.         {
  545.           save_ptr++;
  546.           save_length--;
  547.         }
  548.       memcpy (e_com, save_ptr, save_length);
  549.       text_on_line = e_com;
  550.       e_com += save_length;
  551.       /* We only break if formatting, in which cases there
  552.          are no tabs, only spaces.*/
  553.       column += save_length;
  554.       save_ptr = 0;
  555.     }
  556.       else
  557.     {
  558.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  559.         buf_ptr++;
  560.       if (buf_ptr >= buf_end)
  561.         fill_buffer ();
  562.       text_on_line = 0;
  563.     }
  564.     }
  565. }
  566.